/**
 * Copyright (c) iwindplus Technologies Co., Ltd.2024-2030, All rights reserved.
 */

package com.iwindplus.cloud.feign.decoder;

import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.iwindplus.boot.domain.enums.BizCodeEnum;
import com.iwindplus.boot.domain.exception.BizException;
import com.iwindplus.boot.domain.vo.ResultVO;
import com.iwindplus.boot.util.JacksonUtil;
import com.iwindplus.cloud.feign.domain.property.FeignProperty;
import feign.FeignException;
import feign.Request;
import feign.Response;
import feign.RetryableException;
import feign.codec.ErrorDecoder;
import jakarta.annotation.Resource;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;

/**
 * feign统一异常解码器.
 *
 * @author zengdegui
 * @since 2018/9/1
 */
@Slf4j
public class FeignErrorDecoder extends ErrorDecoder.Default {

    @Resource
    private FeignProperty property;

    @Override
    public Exception decode(String methodKey, Response response) {
        // 默认解码器结果
        Exception exception = super.decode(methodKey, response);

        // 如果禁用自定义错误解码，则直接返回默认结果
        if (!property.getError().getEnabled()) {
            return exception;
        }

        final int status = response.status();
        log.warn("Feign请求失败: 方法={}, 状态码={}", methodKey, status);

        // 特殊异常类型直接返回（如重试异常）
        if (exception instanceof RetryableException) {
            return exception;
        }

        // 处理服务不可用异常
        if (status == HttpStatus.SERVICE_UNAVAILABLE.value()) {
            return new BizException(HttpStatus.SERVICE_UNAVAILABLE);
        }

        // 处理 500-511 状态码范围内的GET请求，开启重试机制
        if (isRetryApplicable(status, response)) {
            return retry(response, exception);
        }
        // 默认处理为内部服务器异常
        ResultVO<Object> result = this.parseException(status, exception);
        return new BizException(result.getBizStatus(), result.getBizCode(), result.getBizMessage(), result.getBizMessageParams());
    }

    /**
     * 判断是否适用重试机制.
     *
     * @param status   状态码
     * @param response 响应
     * @return boolean
     */
    private boolean isRetryApplicable(int status, Response response) {
        return status > HttpStatus.INTERNAL_SERVER_ERROR.value()
            && status <= HttpStatus.NETWORK_AUTHENTICATION_REQUIRED.value()
            && response.request().httpMethod() == Request.HttpMethod.GET
            && Boolean.TRUE.equals(property.getRetry().getEnabled());
    }

    private Exception retry(Response response, Exception exception) {
        Long retryAfter = null;
        return new RetryableException(response.status(), exception.getMessage(), response.request().httpMethod(), exception, retryAfter,
            response.request());
    }

    private ResultVO<Object> parseException(int status, Exception exception) {
        if (!(exception instanceof FeignException feignException)) {
            log.error("非FeignException类型, message={}", exception.getMessage(), exception);

            return ResultVO.error(BizCodeEnum.valueOfBizStatus(status));
        }
        Optional<ByteBuffer> byteBufferOpt = feignException.responseBody();
        if (!byteBufferOpt.isPresent()) {
            return ResultVO.error(BizCodeEnum.RPC_ERROR);
        }

        ByteBuffer byteBuffer = byteBufferOpt.get();
        // 将 ByteBuffer 转换为字符串
        byte[] bytes = new byte[byteBuffer.remaining()];
        byteBuffer.get(bytes);
        String bodyStr = new String(bytes, Charset.defaultCharset());
        if (ObjectUtil.isEmpty(bodyStr)) {
            return ResultVO.error(BizCodeEnum.RPC_ERROR);
        }

        return JacksonUtil.parseObject(bodyStr, new TypeReference<>() {
        });
    }

}
